package cn.powerchaintech.common.cimeparser;

import cn.powerchaintech.common.cimeparser.model.CimEField;
import cn.powerchaintech.common.cimeparser.model.CimEModel;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class CimEDocument {
    private CimEDescription description;
    private List<CimEBlock> cimEBlocks = new ArrayList<>();

    public CimEDocument(CimEDescription description) {
        this.description = description;
    }

    public CimEDocument() {
    }

    public void setDescription(CimEDescription description) {
        this.description = description;
    }

    public int append(CimEBlock cimEBlock) {
        cimEBlocks.add(cimEBlock);
        return cimEBlocks.size();
    }

    public <T> List<T> parseObject(Class<T> cls) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        if (!cls.isAnnotationPresent(CimEModel.class)) {
            throw new UnsupportedOperationException("Class " + cls.getName() + " is not annotated with @CimEModel");
        }
        CimEModel anno = cls.getAnnotation(CimEModel.class);
        String clsName = anno.value();
        CimEBlock black = null;
        for (CimEBlock cb : cimEBlocks) {
            if (cb.getClzName().equals(clsName)) {
                black = cb;
            }
        }
        if (black == null) {
            return null;
        }
        List<T> parseObjs = new ArrayList<>();
        Iterator<Map<String, String>> it = black.iterator();
        while (it.hasNext()) {
            Map<String, String> m = it.next();
            Constructor<T> cons = cls.getDeclaredConstructor();
            cons.setAccessible(true);
            Object tInstance = cons.newInstance();
            for (Field field : cls.getDeclaredFields()) {
                if (field.isAnnotationPresent(CimEField.class)) {
                    Class<?> fieldType = field.getType();
                    field.setAccessible(true);
                    CimEField fieldAnnotation = field.getAnnotation(CimEField.class);
                    String valueStr = fieldAnnotation.value();
                    if (fieldType.equals(int.class) || fieldType.equals(Integer.class)) {
                        field.set(tInstance, Integer.parseInt(m.getOrDefault(valueStr, "0")));
                    }
                    if (fieldType.equals(String.class)) {
                        field.set(tInstance, m.getOrDefault(valueStr, ""));
                    }
                    if (fieldType.equals(double.class) || fieldType.equals(Double.class)) {
                        field.set(tInstance, Double.parseDouble(m.getOrDefault(valueStr, "0.0")));
                    }
                    if (fieldType.equals(long.class) || fieldType.equals(Long.class)) {
                        field.set(tInstance, Long.parseLong(m.getOrDefault(valueStr, "0")));
                    }
                }
            }
            parseObjs.add((T) tInstance);
        }

        return parseObjs;
    }

}
